package cn.bdqn.config.shiro;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import cn.bdqn.pojo.Right;
import cn.bdqn.service.RightService;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Configuration
public class ShiroConfig {
    @Resource
    private RightService rightService;
    /**
     * 开启 Shiro 注解(如@RequiresRoles,@RequiresPermissions),
     * 需借助 SpringAOP 扫描使用 Shiro 注解的类,并在必要时进行安全逻辑验证
     * 配置以下两个 bean(DefaultAdvisorAutoProxyCreator 和
     AuthorizationAttributeSourceAdvisor)
     */
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;


    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(){
        DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(myShiroRealm());
        defaultWebSecurityManager.setRememberMeManager(cookieRememberMeManager());
        return defaultWebSecurityManager;
    }
    /**
     * 开启aop注解支持
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor
    authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor=
                new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    /**
     * 创建数据源
     *
     * @return
     */
    @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm myShiroRealm=new MyShiroRealm();
        //开启缓存
        myShiroRealm.setCachingEnabled(true);
        //开启授权缓存
        myShiroRealm.setAuthorizationCachingEnabled(true);
        //设置密码匹配器
        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        //设置授权缓存名称
        myShiroRealm.setAuthorizationCacheName("authrizationCache");
        return myShiroRealm;

    }

//    /**
//     * 创建安全管理员
//     * @return
//     */
//    @Bean
//    public SecurityManager securityManager(){
//        DefaultSecurityManager securityManager=new DefaultWebSecurityManager();
//                //注入 Realm
//        securityManager.setRealm(myShiroRealm());
//        return securityManager;
//    }

    /**
     * 创建Shiro过滤器
     *
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean factoryBean=
                new ShiroFilterFactoryBean();
            //注入securityManager
        factoryBean.setSecurityManager(securityManager());
            //
        factoryBean.setLoginUrl("/login");
        factoryBean.setSuccessUrl("/main");
        factoryBean.setUnauthorizedUrl("/403");
        Map<String,String> filterMap=new LinkedHashMap<>();
        filterMap.put("/css/**","anon");
        filterMap.put("/fonts/**","anon");
        filterMap.put("/images/**","anon");
        filterMap.put("/js/**","anon");
        filterMap.put("/localcss/**","anon");
        filterMap.put("/localjs/**","anon");
        filterMap.put("/dologin","anon");
        filterMap.put("/logout","logout");
//            //静态演示
//        filterMap.put("/user/list","perms[用户列表]");
//        filterMap.put("/user/add","perms[用户添加]");
//        filterMap.put("/user/edit","perms[用户编辑]");
//        filterMap.put("/user/delete","perms[用户删除]");
        //动态授权
        List<Right> rights = rightService.findAllRights();
        for (Right right : rights) {
            if(right.getRightUrl()!=null&& !right.getRightUrl().trim().equals("")){
                filterMap.put(right.getRightUrl(),"perms["+right.getRightCode()+"]");
            }
        }
    //配置认证访问：其他资源(URL)必须认证通过才能访问
        //必须放在过滤器链的最后面
        filterMap.put("/**","authc");
        factoryBean.setFilterChainDefinitionMap(filterMap);
        return factoryBean;
    }

    /**
     * cookie对象
     *
     * @return
     */
    @Bean
    public SimpleCookie simpleCookie() {
        //这个参数是cookie的名称，对应前端的checkbox的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //记住我cookie生效时间为一天 ,单位秒
        simpleCookie.setMaxAge(60 * 24 * 24);
        return simpleCookie;
    }

    /**
     * cookie管理对象
     *
     * @return
     */
    @Bean
    public CookieRememberMeManager cookieRememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager =
                new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(simpleCookie());
            //rememberMe cookie加密的密钥 建议每个项目都不一样
            // 默认AES算法 密钥长度(128 256 512 位)
        cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
        return cookieRememberMeManager;
    }

    @Bean
    public SecurityManager securityManager() {
            //1. 创建SecurityManager
        DefaultWebSecurityManager securityManager =
                new DefaultWebSecurityManager();
            //2. 注入realm属性
        securityManager.setRealm(myShiroRealm());
            //3. 注入记住我
        securityManager.setRememberMeManager(cookieRememberMeManager());
        securityManager.setCacheManager(redisCacheManager());
        return securityManager;
    }
    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

    /**
     * redis管理对象
     * @return
     */
    @Bean
    public RedisManager redisManager(){
        RedisManager redisManager=new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);
        return redisManager;
    }
    /**
     * sessionDao对象
     * @return
     */
    @Bean
    public RedisSessionDAO redisSessionDAO(){
        RedisSessionDAO redisSessionDAO=
                new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }
    /**
     * session管理对象
     * @return
     */
    @Bean
    public DefaultWebSessionManager defaultWebSessionManager(){
        DefaultWebSessionManager defaultWebSessionManager=
                new DefaultWebSessionManager();
        defaultWebSessionManager.setSessionDAO(redisSessionDAO());
        return defaultWebSessionManager;
    }
    /**
     * 缓存管理对象
     * @return
     */
    @Bean
    public RedisCacheManager redisCacheManager(){
        RedisCacheManager redisCacheManager=
                new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        //设置缓存名称
        redisCacheManager.setPrincipalIdFieldName("usrName");
        //缓存有效期 30分钟
        redisCacheManager.setExpire(60*30);
        return redisCacheManager;
    }
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher=
                new HashedCredentialsMatcher();
            //设置加密算法
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
            //设置加密次数
        hashedCredentialsMatcher.setHashIterations(2);
        return hashedCredentialsMatcher;
    }
}

